# -*- coding: utf8 -*-
########################################################################
# Copyright (c) 2008 Burdakov Daniel <kreved@kreved.org>               #
#                                                                      #
# This file is part of PyWoW.                                          #
#                                                                      #
# PyWoW is free software: you can redistribute it and/or modify        #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or    #
# (at your option) any later version.                                  #
#                                                                      #
# PyWoW is distributed in the hope that it will be useful,             #
# but WITHOUT ANY WARRANTY; without even the implied warranty of       #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        #
# GNU General Public License for more details.                         #
#                                                                      #
# You should have received a copy of the GNU General Public License    #
# along with PyWoW.     If not, see <http://www.gnu.org/licenses/>.    #
########################################################################

import sys
from twisted.internet import reactor
from pywow import realmserver, realmclient, worldserver, worldclient, errors
from pywow.constants import *
from pywow.opcodes import opcodes

class RealmServerFactory(realmserver.RealmServerFactory):
 def __init__(self, passwd):
  self.passwd = passwd
  realmserver.RealmServerFactory.__init__(self)
 def getSV(self, username):
  if username in self.passwd.keys():
   return self.generateSV(username, self.passwd[username])
  else:
   raise errors.NoSuchUser, username

class RealmClientFactory(realmclient.RealmClientFactory):
 def __init__(self, secondConnection):
  self.secondConnection = secondConnection
 def onRealmList(self, realms, K):
  if realms:
   realm = realms[0]
   address = realm[4]
   name = realm[3]
   host, port = address.split(':')
   self.worldClient.setAuthData(self.username, K)
   reactor.connectTCP(host, int(port), self.worldClient)
  else:
   self.secondConnection.secondConnectionLost("No realms available.")
 def authFailed(self, reason):
  self.secondConnection.secondConnectionLost(reason)
 def clientConnectionFailed(self, connector, reason):
  self.secondConnection.secondConnectionLost(reason)

class WorldClientProtocol(worldclient.WorldClientProtocol):
 secondConnection = None
 def connectionMade(self):
  self.secondConnection = self.factory.secondConnection
  worldclient.WorldClientProtocol.connectionMade(self)
 def connectionLost(self, reason):
  if self.secondConnection: self.secondConnection.secondConnectionLost(reason)
  worldclient.WorldClientProtocol.connectionLost(self, reason)
 def secondConnectionLost(self):
  self.secondConnection = None
  self.transport.loseConnection()
 def handlePacket(self, opcode, body):
  if self.secondConnection: self.secondConnection.handleServerPacket(opcode, body)

class WorldClientFactory(worldclient.WorldClientFactory):
 protocol = WorldClientProtocol
 def __init__(self, secondConnection):
  self.secondConnection = secondConnection
 def authFailed(self, reason):
  self.secondConnection.secondConnectionLost(reason)
 def authDone(self, session, tbc):
  self.secondConnection.secondConnectionEstablished(session)
 def clientConnectionFailed(self, connector, reason):
  self.secondConnection.secondConnectionLost(reason)

class ProxyServerProtocol(worldserver.WorldServerProtocol):
 def connectionMade(self):
  self.secondConnection = None
  self.queue = []
  self.connected = True
  worldserver.WorldServerProtocol.connectionMade(self)
 def handlePacket(self, opcode, body):
  self.handleClientPacket(opcode, body)
 def handleClientPacket(self, opcode, body):
  """Here may be some analysis or filters"""
  self.sendToServer(opcode, body)
 def handleServerPacket(self, opcode, body):
  """Here may be some analysis or filters"""
  self.sendToClient(opcode, body)
 def sendToServer(self, opcode, body):
  if self.secondConnection is None:
   if self.queue == []:
    self.establishSecondConnection()
   self.queue.append((opcode, body))
  else:
   self.secondConnection.send(opcode, body)
 def sendToClient(self, opcode, body):
  self.send(opcode, body)
 def establishSecondConnection(self):
  r = RealmClientFactory(self)
  w = WorldClientFactory(self)
  r.setAuthData(self.username, self.factory.passwd[self.username])
  r.worldClient = w
  reactor.connectTCP(self.factory.connectHost, self.factory.connectPort, r)
 def connectionLost(self, reason):
  self.connected = False
  if self.secondConnection: self.secondConnection.secondConnectionLost()
 def secondConnectionEstablished(self, connection):
  if self.connected:
   self.secondConnection = connection
   while self.queue:
    opcode, body = self.queue.pop(0)
    self.sendToServer(opcode, body)
  else: connection.secondConnectionLost()
 def secondConnectionLost(self, reason):
  self.secondConnection = None
  if self.connected: self.transport.loseConnection()

class ProxyServerFactory(worldserver.WorldServerFactory):
 protocol = ProxyServerProtocol
 def __init__(self, connectHost, connectPort=3724, passwd={}, *args, **kwargs):
  self.connectHost, self.connectPort, self.passwd = connectHost, connectPort, passwd
  worldserver.WorldServerFactory.__init__(self, *args, **kwargs)
